﻿// ***********************************************************************
// Assembly         : Delta_control
// Author           : Juan Alberto Cerino Gomez
// Created          : 02-18-2013
//
// Last Modified By : Juan Alberto Cerino Gomez
// Last Modified On : 06-04-2013
// ***********************************************************************
// <copyright file="ControlBase.cs" company="Delta Bussines">
//     Copyright (c) 2013  Delta Bussines. All rights reserved.
// </copyright>
// <summary></summary>
// ***********************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Delta_entidad.Base;
using Delta_bussines.Base;
using Delta_entidad.EntidadesControl;
using System.Xml;
using System.Data;
using System.IO;
using Delta_util.Clases;
using Delta_entidad.Atributos;
using Delta_bussines.PersistenciaControl;

namespace Delta_control.Base
{
    /// <summary>
    /// Clase principal que se encarga de realizar las operaciones basicas de una tabla tales como:
    /// <<br/>Insertar/Actualizar
    /// <br/>Eliminar
    /// <br/>Obtener
    /// </summary>
    /// <typeparam name="D"></typeparam>
    [Serializable()]
    public class ControlBase<D> where D : TipoBase, new()
    {
        /// <summary>
        /// Variable que representa una lista de entidades.
        /// </summary>
        private List<D> _Lista;



        /// <summary>
        /// Variable que representa una entidad.
        /// </summary>
        private D _Dato;
        /// <summary>
        /// Variable que representa la persistencia.
        /// </summary>
        public PerConfig<D> persistencia = new PerConfig<D>();
        /// <summary>
        /// Variable que representa el valor que indica si se debe devolver la excepcion a la clase que invoca el metodo.
        /// </summary>
        private bool DevolverError = true;
        /// <summary>
        /// Variable que representa el control primario.
        /// </summary>
        private object ControlPrimario = null;


        /// <summary>
        /// Obtiene el tipo de dato de la entidad que fue configurado para este control.
        /// </summary>
        /// <value>Tipo de dato de la entidad.</value>
        public Type TipoEntidadBase { get { return typeof(D); } }
        /// <summary>
        /// Obtiene la configuración dinámica del tipo de dato configurado para este control.
        /// </summary>
        /// <value>Lista de configuración dinámica.</value>
        public List<dynamic> ConfiguracionDatosUsers
        {
            get
            {

                Cat_tipo_gral info = persistencia.ConfigCamposUsers;
                if (info != null)
                    return info.campos.ToList<dynamic>();
                else
                    return null;
            }
        }
        /// <summary>
        /// Obtiene la configuración del tipo general del tipo de dato configurado para este control.
        /// </summary>
        /// <value>Configuración del tipo general.</value>
        public Cat_tipo_gral InformacionUsers
        {
            get { return persistencia.ConfigCamposUsers; }
        }
        /// <summary>
        /// Obtiene la persistencia primaria, esta persistencia se toma del control primario, es decir, el control del cual se tomará la conexión y transacción.
        /// </summary>
        /// <value>Persistencia primaria.</value>
        internal IPersistencia PersistenciaPrimaria
        {
            get
            {
                object persisPrimaria = null;
                if (ControlPrimario != null)
                    persisPrimaria = Comun.ObtenerDato(ControlPrimario, "persistencia");
                if (ControlPrimario != null && persisPrimaria != null)
                    return (IPersistencia)persisPrimaria;
                else
                    return null;
            }
        }
        /// <summary>
        /// Metodo que se encarga de seleccionar una entidad del listado, de acuerdo al indice especificado.
        /// </summary>
        /// <param name="indice">Indice o numero de registro a seleccionar, en base 0.</param>
        public void SeleccionarIndice(int indice)
        {
            Dato = Lista[indice];
        }

        /// <summary>
        /// Metodo que se encarga de crear una nueva entidad y asignar la configuración dinámica configurada para el tipo de entidad del control.
        /// </summary>
        /// <returns>Devuelve la nueva entidad creada.</returns>
        public void CrearEntidad()
        {
            Dato = new D();
            Dato.FijarConfiguracionDinamica(InformacionUsers);


        }
        /// <summary>
        /// Obtiene o establece la lista de entidades.
        /// </summary>
        /// <value>Lista de entidades.</value>
        public List<D> Lista
        {
            get
            {
                if (_Lista == null)
                    _Lista = new List<D>();
                return _Lista;
            }
            set { _Lista = value; }
        }

        /// <summary>
        /// Obtiene o establece la lista de entidades dinamicas.
        /// </summary>
        /// <value>Lista de entidades.</value>
        public List<ItemGral> ListaDinamica
        {
            get;
            set;

        }

        /// <summary>
        /// Obtiene o esatblece la entidad que actualmente esta usando el control.
        /// </summary>
        /// <value>]Datos de la entidad.</value>
        public D Dato
        {
            get { return _Dato; }
            set { _Dato = value; }
        }


        /// <summary>
        /// Metodo que se encarga de procesar una excepción, es decir, si la propiedad DevolverError es "true" entonces se genera una nueva excepción, en caso contrario no se genera ninguna excepción
        /// y el metodo detiene su ejecución en el punto donde se generá le excepción y no informa al usuario del error.
        /// </summary>
        /// <param name="ex">Datos de la excepción.</param>
        /// <exception cref="System.Exception"></exception>
        protected internal void ProcesarExcepcion(Exception ex)
        {
            if (DevolverError)
                throw new Exception(ex.Message, ex.InnerException);
            //Registrar en la bitacora de errores

        }

        #region Metodos Genericos

        /// <summary>
        /// Metodo que se encarga de obtener los datos de un registro de la base de datos.
        /// <br/>El dato es guardado en la entidad Dato.
        /// </summary>
        /// <param name="entidad">Valores de los parametros. Si la entidad es NULL, entonces se toma los datos de la propiedad "Dato".</param>
        public void Obtener(D entidad = default(D))
        {
            try
            {

                if (entidad != null)
                    Dato = entidad;
                Dato = persistencia.Obtener(Dato, PersistenciaPrimaria);
                if (Dato != null)
                    Dato.FijarConfiguracionDinamica(InformacionUsers);
            }
            catch (Exception ex)
            {
                ProcesarExcepcion(ex);
            }
            finally
            {


            }
        }
        /// <summary>
        /// Metodo que se encarga de ejecutar un procedimiento almacenado y devuelve el resultado en un DataTable.
        /// </summary>
        /// <param name="comando">Nombre del procedimiento almacenado a ejecutar.</param>
        /// <param name="aplicarFiltro">Indica si se debe aplicar los filtros configurados para el tipo de dato de la entidad.</param>
        /// <param name="datosFiltro">Datos del filtro, es decir, los valores a aplicar en el filtro.</param>
        /// <param name="infoConfig">Configuración dinámica, de la cual se va a obtener las operaciones de filtro.</param>
        /// <param name="parametros">Lista de parametros para la consulta.</param>
        /// <returns>Devuelve la tabla con el resultado de la ejecución.</returns>
        public DataTable EjecutarComando(string comando, bool aplicarFiltro = false, TipoBase datosFiltro = null, List<Cat_campo_tecnico> infoConfig = null, Dictionary<string, object> parametros = null)
        {
            try
            {
                DataTable tb = persistencia.EjecutarComando(comando, PersistenciaPrimaria, parametros);
                DataTable ntabla = tb.Clone();
                string strfiltro = null;
                if (aplicarFiltro && datosFiltro != null && infoConfig != null)
                {
                    foreach (Cat_campo_tecnico campo_filtro in infoConfig)
                    {
                        object valor = datosFiltro.ObtenerValor(campo_filtro.nombre);
                        if (valor != null && !string.IsNullOrWhiteSpace(valor.ToString()))
                        {
                            string init = campo_filtro.tipo.tipo_bd.ToUpper().Contains("CHAR") || campo_filtro.tipo.tipo_bd.ToUpper().Contains("TEXT") ? "'" : "";
                            string charLike = campo_filtro.filtro.operacion.ToUpper() == "LIKE" ? "%" : "";
                            if (strfiltro == null)
                                strfiltro = string.Format("{0} {1} {2}{3}{4}{3}{2}", campo_filtro.nombre, campo_filtro.filtro.operacion, init, charLike, valor);
                            else
                                strfiltro += string.Format(" or {0} {1} {2}{3}{4}{3}{2}", campo_filtro.nombre, campo_filtro.filtro.operacion, init, charLike, valor);
                        }
                    }

                }
                if (!string.IsNullOrWhiteSpace(strfiltro))
                {
                    foreach (DataRow dr in tb.Select(strfiltro))
                        ntabla.ImportRow(dr);
                    return ntabla;
                }
                else
                    return tb;

            }
            catch (Exception ex)
            {
                ProcesarExcepcion(ex);
                return null;
            }
            finally
            {


            }
        }

        /// <summary>
        /// Metodo que se encarga de crear una nueva conexión en la persistencia.
        /// </summary>
        /// <param name="ControlPrimario">Control del cual se va a tomar la conexión/transacción.</param>
        /// <param name="iniciarTransaccion">Indica si la conexión manejará transacción.</param>
        /// <param name="finalizarManualmente">Indica si la conexión y transacción se finaliza fuera del control.</param>
        public void CrearConexion(object ControlPrimario = null, bool iniciarTransaccion = false, bool finalizarManualmente = false)
        {

            this.ControlPrimario = ControlPrimario;
            if (ControlPrimario != null)
                persistencia.HeredarConexionTransaccionDe(Comun.ObtenerDato(ControlPrimario, "persistencia"));
            else
                persistencia.ObtenerConexion(iniciarTransaccion);
            if (finalizarManualmente)
            {
                persistencia.CerrarConexionManual = true;
                persistencia.CompartiendoConexion = true;
            }

        }

        /// <summary>
        /// Metodo que se encarga de finalizar una transacción que ejecuta querys en lotes.
        /// </summary>
        /// <param name="estatus">Indica si se confirma(true) o rechaza la transacción (false).</param>
        public void ConfirmarTransaccion(bool estatus = true)
        {
            persistencia.FinalizarTransaccion(estatus);
            persistencia.LiberarConexion();
        }

        /// <summary>
        /// Metodo que se encarga de cargar la configuración dinámica al control.
        /// </summary>
        /// <param name="informacion">Configuración dinámica.</param>
        public void AsignarInformacionDinamica(Cat_tipo_gral informacion)
        {
            persistencia.ConfigCamposUsers = informacion;
        }

        /// <summary>
        /// Metodo que se encarga de obtener la configuración dinámica configurada para un tipo de dato.
        /// </summary>
        /// <param name="tipo">El tipo de dato del cual se quiere obtener la configuración dinámica.</param>
        /// <param name="id_tipo_gral">Clave del tipo general del cual se quiere obtener la configuración dinámica.</param>
        public void CargarConfiguracionUser(Type tipo = null, int? id_tipo_gral = null)
        {

            try
            {
                if (InformacionUsers != null && InformacionUsers.campos.Count > 0 && (InformacionUsers.id_tipo_gral == id_tipo_gral || id_tipo_gral == null))
                    return;
                if (tipo == null && id_tipo_gral == null)
                    tipo = typeof(D);
                persistencia.ConfigCamposUsers = null;
                PerDatosDinamicos dtDin = new PerDatosDinamicos();
                persistencia.ConfigCamposUsers = dtDin.ObtenerCamposUserTipo(tipo, id_tipo_gral, PersistenciaPrimaria);

            }
            catch (Exception ex)
            {
                ProcesarExcepcion(ex);
            }
            finally
            {


            }

        }
        /// <summary>
        /// Metodo que se encarga de obtener una lista de entidades, este metodo ejecuta la operación OBTENER VARIOS.
        /// <br/>El resultado lo guarda en la propiedad Listado.
        /// </summary>
        /// <param name="entidad">Entidad que contiene los valores de los parametros.Si la entidad es NULL, entonces se toma los datos de la propiedad "Dato"</param>
        /// <param name="agregarSeleccione">Indica si se debe agregar una entidad vacia.</param>
        public void ObtenerListado(D entidad = default(D), int agregarSeleccione = 0)
        {
            try
            {

                if (entidad != null)
                    Dato = entidad;


                // Dato.FijarValor("agregar_seleccione", agregarSeleccione);
                Lista = persistencia.ObtenerVarios(Dato, PersistenciaPrimaria);

                foreach (D dato in Lista)
                {
                    dato.FijarConfiguracionDinamica(InformacionUsers);
                }
                if (agregarSeleccione == 1)
                    Lista.Insert(0, new D());
            }
            catch (Exception ex)
            {
                ProcesarExcepcion(ex);
            }
            finally
            {


            }
        }


        /// <summary>
        /// Metodo que se encarga de insertar/actualizar los datos de una entidad. Este metodo ejecuta la operación de INSERTAR/ACTUALIZAR.
        /// </summary>
        /// <param name="datos">Los datos a insertar/actualizar.Si la entidad es NULL, entonces se toma los datos de la propiedad "Dato"</param>
        /// <param name="finalizar">Indica si debe finalizar la conexión y transacción.</param>
        public void Insertar(D datos = default(D), bool finalizar = true)
        {

            try
            {

                if (datos != null)
                    Dato = datos;
                persistencia.Insertar<D>(Dato, PersistenciaPrimaria);
                if (PersistenciaPrimaria == null && finalizar)
                    persistencia.FinalizarTransaccion();
            }
            catch (Exception ex)
            {
                if (PersistenciaPrimaria == null && finalizar)
                    persistencia.FinalizarTransaccion(false);

                ProcesarExcepcion(ex);
            }
            finally
            {
                if (PersistenciaPrimaria == null && finalizar)
                    persistencia.LiberarConexion();

            }



        }

        /// <summary>
        /// Metodo que se encarga de eliminar un registro. Este metodo ejecuta la operación ELIMINAR.
        /// </summary>
        /// <param name="entidad">Datos del registro a eliminar. Si la entidad es NULL, entonces se toma los datos de la propiedad "Dato".</param>
        /// <param name="finalizar">Indica si debe finalizar la conexión y transacción.</param>
        public void Eliminar(D entidad = default(D), bool finalizar = true)
        {

            try
            {

                if (entidad != null)
                    Dato = entidad;

                persistencia.Eliminar(Dato, PersistenciaPrimaria);
                if (PersistenciaPrimaria == null && finalizar)
                    persistencia.FinalizarTransaccion();
            }
            catch (Exception ex)
            {
                if (PersistenciaPrimaria == null && finalizar)
                    persistencia.FinalizarTransaccion(false);

                ProcesarExcepcion(ex);
            }
            finally
            {
                if (PersistenciaPrimaria == null && finalizar)
                    persistencia.LiberarConexion();

            }



        }


        /// <summary>
        /// Metodo que se encarga de limpiar la memoria del control.
        /// </summary>
        public void LimpiarDato()
        {

            Lista = new List<D>();
            Dato = null;
        }

        /// <summary>
        /// Metodo que se encarga de convertir el listado en un DataView.
        /// </summary>
        /// <param name="aplicarFiltro">Indica si se debe aplicar los filtros configurados para el tipo de dato de la entidad.</param>
        /// <param name="datosFiltro">Datos del filtro, es decir, los valores a aplicar en el filtro.</param>
        /// <param name="infoConfig">Configuración dinámica, de la cual se va a obtener las operaciones de filtro.</param>
        /// <param name="filtroDinamico">Permite asignar una lista de filtros para la lista</param>
        /// <returns>Devuelve el DataView con los datos del Listado.</returns>
        public DataView ListaATabla(bool aplicarFiltro = false, TipoBase datosFiltro = null, List<Cat_campo_tecnico> infoConfig = null, Dictionary<string, object> filtroDinamico = null)
        {

            DataTable dt = new DataTable();

            //if (typeof(D) != typeof(TablasGral))
            if (true)
                //Se agregan las columnas a la tabla
                foreach (PropertyInfo prop in typeof(D).GetProperties())
                {
                    if (!Comun.PropiedadDinamica(prop.Name, ConfiguracionDatosUsers))
                    {
                        if (Comun.ObtenerAtributoEntidad<AttPropiedad>(typeof(D), prop.Name) != null)
                        {
                            if (prop.CanRead)
                            {
                                dt.Columns.Add(new DataColumn { ColumnName = prop.Name, DataType = prop.PropertyType.IsGenericType ? prop.PropertyType.GetGenericArguments()[0] : prop.PropertyType });

                            }
                        }
                    }
                }

            //Se agregan las columnas dinamicas

            if (ConfiguracionDatosUsers != null)
                foreach (Cat_campo_tecnico elemento in ConfiguracionDatosUsers)
                {
                    Type tipoPropiedad = Type.GetType(elemento.tipo.tipo_codigo);
                    if (tipoPropiedad.IsGenericType)
                        tipoPropiedad = tipoPropiedad.GetGenericArguments()[0];
                    dt.Columns.Add(new DataColumn { ColumnName = elemento.nombre, DataType = tipoPropiedad });

                }


            //Aqui se insertan los registros
            if (typeof(D) == typeof(TablasGral))
            {
                dt.Columns.Add("Fila", typeof(int));
                if (Dato != null && !string.IsNullOrWhiteSpace((Dato as TablasGral).dato))
                    //foreach (ItemGral item in Dato.ObtenerITemsTabla(persistencia.ConfigCamposUsers, (Dato as TablasGral).id_tabla_gral, (Dato as TablasGral).id_tipo_gral, filtroDinamico))
                    if (ListaDinamica == null)
                        ListaDinamica = Dato.ObtenerITemsTabla(persistencia.ConfigCamposUsers, (Dato as TablasGral).id_tabla_gral, (Dato as TablasGral).id_tipo_gral, filtroDinamico);
                foreach (ItemGral item in ListaDinamica)
                {
                    DataRow nfila = dt.NewRow();
                    foreach (DataColumn columna in dt.Columns)
                        nfila[columna.ColumnName] = item.ObtenerValor(columna.ColumnName, DBNull.Value);
                    dt.Rows.Add(nfila);
                }
            }
            else
                foreach (D entidad in Lista)
                {
                    DataRow nfila = dt.NewRow();
                    foreach (DataColumn columna in dt.Columns)
                        nfila[columna.ColumnName] = entidad.ObtenerValor(columna.ColumnName, DBNull.Value);
                    dt.Rows.Add(nfila);

                }

            DataTable ntabla = dt.Clone();

            string strfiltro = null;
            if (aplicarFiltro && datosFiltro != null && infoConfig != null)
            {
                foreach (Cat_campo_tecnico campo_filtro in infoConfig)
                {
                    object valor = datosFiltro.ObtenerValor(campo_filtro.nombre);
                    if (valor != null && !string.IsNullOrWhiteSpace(valor.ToString()))
                    {
                        string init = campo_filtro.tipo.tipo_bd.ToUpper().Contains("CHAR") || campo_filtro.tipo.tipo_bd.ToUpper().Contains("TEXT") ? "'" : "";
                        string charLike = campo_filtro.filtro.operacion.ToUpper() == "LIKE" ? "%" : "";
                        if (strfiltro == null)
                            strfiltro = string.Format("{0} {1} {2}{3}{4}{3}{2}", campo_filtro.nombre, campo_filtro.filtro.operacion, init, charLike, valor);
                        else
                            strfiltro += string.Format(" and {0} {1} {2}{3}{4}{3}{2}", campo_filtro.nombre, campo_filtro.filtro.operacion, init, charLike, valor);
                    }
                }

            }
            foreach (DataRow dr in dt.Select(strfiltro))
                ntabla.ImportRow(dr);
            return ntabla.DefaultView;

        }

        /// <summary>
        /// Metodo que se encarga de obtener una fila de una tabla dinámica.
        /// </summary>
        /// <param name="fila">Número de la fila que se quiere obtener.</param>
        /// <returns>Datos de la entidad.</returns>
        public ItemGral ObtenerDatosItemGral(int fila)
        {
            List<ItemGral> listado = ObtenerListadoTablaXML();
            if (listado.Count >= fila && fila <= listado.Count)
                return listado[fila - 1];
            else
                return new ItemGral();
        }
        /// <summary>
        /// Metodo que se encarga de convertir una cadena XML en una lista de entidades dinámicas. 
        /// </summary>
        /// <param name="datosFiltro">Permite asignar una lista de filtros para la lista</param>
        /// <returns>Listado de entidades dinámicas.</returns>
        public List<ItemGral> ObtenerListadoTablaXML(IDictionary<string, object> datosFiltro = null)
        {
            if (Dato != null)
                return Dato.ObtenerITemsTabla(persistencia.ConfigCamposUsers, (Dato as TablasGral).id_tabla_gral, (Dato as TablasGral).id_tipo_gral, datosFiltro as Dictionary<string, object>);
            else
                return new List<ItemGral>();
        }


        #endregion

    }
}
